#!/usr/bin/env python3
"""
ESP32摄像头配置和初始化模块

基于esp32-camera库实现摄像头驱动接口，支持多种传感器型号和动态配置。
实现需求1.1, 1.2, 1.3：实时视频采集系统的配置和初始化。
"""

import logging
from enum import Enum
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Tuple, Any
import json
import asyncio
from pathlib import Path

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class CameraModel(Enum):
    """支持的摄像头传感器型号"""
    OV2640 = "OV2640"
    OV5640 = "OV5640" 
    OV3660 = "OV3660"
    OV5642 = "OV5642"
    OV7725 = "OV7725"
    NT99141 = "NT99141"
    GC2145 = "GC2145"
    GC032A = "GC032A"
    GC0308 = "GC0308"
    BF3005 = "BF3005"


class FrameSize(Enum):
    """支持的分辨率"""
    QQVGA = (160, 120)      # 160x120
    QCIF = (176, 144)       # 176x144
    HQVGA = (240, 176)      # 240x176
    QVGA = (320, 240)       # 320x240
    CIF = (400, 296)        # 400x296
    VGA = (640, 480)        # 640x480
    SVGA = (800, 600)       # 800x600
    XGA = (1024, 768)       # 1024x768
    SXGA = (1280, 1024)     # 1280x1024
    UXGA = (1600, 1200)     # 1600x1200
    QXGA = (2048, 1536)     # 2048x1536
    HD = (1280, 720)        # 1280x720
    FHD = (1920, 1080)      # 1920x1080
    P_HD = (720, 1280)      # 720x1280 (Portrait)
    P_3MP = (864, 1536)     # 864x1536 (Portrait)
    QSXGA = (2560, 1920)    # 2560x1920


class PixelFormat(Enum):
    """支持的像素格式"""
    RGB565 = "RGB565"
    YUV422 = "YUV422"
    GRAYSCALE = "GRAYSCALE"
    JPEG = "JPEG"
    RGB888 = "RGB888"
    RAW = "RAW"
    RGB444 = "RGB444"
    RGB555 = "RGB555"


@dataclass
class CameraCapabilities:
    """摄像头能力描述"""
    model: CameraModel
    supported_resolutions: List[FrameSize]
    supported_formats: List[PixelFormat]
    max_fps: int
    min_fps: int
    has_autofocus: bool = False
    has_flash: bool = False
    sensor_id: Optional[int] = None


@dataclass
class CameraConfig:
    """ESP32摄像头配置"""
    # 基本配置
    model: CameraModel = CameraModel.OV2640
    frame_size: FrameSize = FrameSize.VGA
    pixel_format: PixelFormat = PixelFormat.JPEG
    
    # 质量和性能配置
    jpeg_quality: int = 12  # 1-63, 数值越小质量越高
    frame_buffer_count: int = 2  # 帧缓冲区数量
    grab_mode: int = 0  # 0=when empty, 1=latest
    
    # 帧率配置
    fps: int = 15
    xclk_freq_hz: int = 20000000  # 20MHz
    
    # 图像处理配置
    brightness: int = 0      # -2 to 2
    contrast: int = 0        # -2 to 2
    saturation: int = 0      # -2 to 2
    sharpness: int = 0       # -2 to 2
    denoise: int = 0         # 0 to 8
    
    # 自动控制配置
    auto_exposure_ctrl: bool = True
    auto_exposure_level: int = 0  # -2 to 2
    manual_exposure_value: int = 300
    auto_gain_ctrl: bool = True
    gain_ceiling: int = 0    # 0 to 6
    manual_gain_value: int = 0
    
    # 白平衡配置
    white_balance: bool = True
    white_balance_mode: int = 0  # 0=auto, 1=sunny, 2=cloudy, 3=office, 4=home
    
    # 其他配置
    horizontal_mirror: bool = False
    vertical_flip: bool = False
    color_bar: bool = False
    
    # 引脚配置 (ESP32-CAM默认配置)
    pin_config: Dict[str, int] = field(default_factory=lambda: {
        'pin_pwdn': 32,
        'pin_reset': -1,
        'pin_xclk': 0,
        'pin_sscb_sda': 26,
        'pin_sscb_scl': 27,
        'pin_d7': 35,
        'pin_d6': 34,
        'pin_d5': 39,
        'pin_d4': 36,
        'pin_d3': 21,
        'pin_d2': 19,
        'pin_d1': 18,
        'pin_d0': 5,
        'pin_vsync': 25,
        'pin_href': 23,
        'pin_pclk': 22,
    })
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        return {
            'model': self.model.value,
            'frame_size': {
                'name': self.frame_size.name,
                'width': self.frame_size.value[0],
                'height': self.frame_size.value[1]
            },
            'pixel_format': self.pixel_format.value,
            'jpeg_quality': self.jpeg_quality,
            'frame_buffer_count': self.frame_buffer_count,
            'grab_mode': self.grab_mode,
            'fps': self.fps,
            'xclk_freq_hz': self.xclk_freq_hz,
            'image_processing': {
                'brightness': self.brightness,
                'contrast': self.contrast,
                'saturation': self.saturation,
                'sharpness': self.sharpness,
                'denoise': self.denoise,
            },
            'auto_controls': {
                'auto_exposure_ctrl': self.auto_exposure_ctrl,
                'auto_exposure_level': self.auto_exposure_level,
                'manual_exposure_value': self.manual_exposure_value,
                'auto_gain_ctrl': self.auto_gain_ctrl,
                'gain_ceiling': self.gain_ceiling,
                'manual_gain_value': self.manual_gain_value,
            },
            'white_balance': {
                'enabled': self.white_balance,
                'mode': self.white_balance_mode,
            },
            'orientation': {
                'horizontal_mirror': self.horizontal_mirror,
                'vertical_flip': self.vertical_flip,
            },
            'debug': {
                'color_bar': self.color_bar,
            },
            'pin_config': self.pin_config
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'CameraConfig':
        """从字典创建配置"""
        config = cls()
        
        # 基本配置
        if 'model' in data:
            config.model = CameraModel(data['model'])
        
        if 'frame_size' in data:
            frame_data = data['frame_size']
            if isinstance(frame_data, dict) and 'name' in frame_data:
                config.frame_size = FrameSize[frame_data['name']]
            elif isinstance(frame_data, str):
                config.frame_size = FrameSize[frame_data]
        
        if 'pixel_format' in data:
            config.pixel_format = PixelFormat(data['pixel_format'])
        
        # 质量配置
        for attr in ['jpeg_quality', 'frame_buffer_count', 'grab_mode', 'fps', 'xclk_freq_hz']:
            if attr in data:
                setattr(config, attr, data[attr])
        
        # 图像处理配置
        if 'image_processing' in data:
            img_proc = data['image_processing']
            for attr in ['brightness', 'contrast', 'saturation', 'sharpness', 'denoise']:
                if attr in img_proc:
                    setattr(config, attr, img_proc[attr])
        
        # 自动控制配置
        if 'auto_controls' in data:
            auto_ctrl = data['auto_controls']
            for attr in ['auto_exposure_ctrl', 'auto_exposure_level', 'manual_exposure_value',
                        'auto_gain_ctrl', 'gain_ceiling', 'manual_gain_value']:
                if attr in auto_ctrl:
                    setattr(config, attr, auto_ctrl[attr])
        
        # 白平衡配置
        if 'white_balance' in data:
            wb = data['white_balance']
            if 'enabled' in wb:
                config.white_balance = wb['enabled']
            if 'mode' in wb:
                config.white_balance_mode = wb['mode']
        
        # 方向配置
        if 'orientation' in data:
            orient = data['orientation']
            if 'horizontal_mirror' in orient:
                config.horizontal_mirror = orient['horizontal_mirror']
            if 'vertical_flip' in orient:
                config.vertical_flip = orient['vertical_flip']
        
        # 调试配置
        if 'debug' in data:
            debug = data['debug']
            if 'color_bar' in debug:
                config.color_bar = debug['color_bar']
        
        # 引脚配置
        if 'pin_config' in data:
            config.pin_config.update(data['pin_config'])
        
        return config


class ESP32CameraManager:
    """ESP32摄像头管理器"""
    
    # 摄像头能力数据库
    CAMERA_CAPABILITIES = {
        CameraModel.OV2640: CameraCapabilities(
            model=CameraModel.OV2640,
            supported_resolutions=[
                FrameSize.QQVGA, FrameSize.QCIF, FrameSize.HQVGA, FrameSize.QVGA,
                FrameSize.CIF, FrameSize.VGA, FrameSize.SVGA, FrameSize.XGA,
                FrameSize.SXGA, FrameSize.UXGA
            ],
            supported_formats=[PixelFormat.JPEG, PixelFormat.RGB565, PixelFormat.YUV422, PixelFormat.GRAYSCALE],
            max_fps=60,
            min_fps=1,
            has_autofocus=False,
            sensor_id=0x2642
        ),
        CameraModel.OV5640: CameraCapabilities(
            model=CameraModel.OV5640,
            supported_resolutions=[
                FrameSize.QVGA, FrameSize.CIF, FrameSize.VGA, FrameSize.SVGA,
                FrameSize.XGA, FrameSize.SXGA, FrameSize.UXGA, FrameSize.QXGA,
                FrameSize.HD, FrameSize.FHD, FrameSize.QSXGA
            ],
            supported_formats=[PixelFormat.JPEG, PixelFormat.RGB565, PixelFormat.YUV422, PixelFormat.RAW],
            max_fps=60,
            min_fps=1,
            has_autofocus=True,
            sensor_id=0x5640
        ),
        CameraModel.OV3660: CameraCapabilities(
            model=CameraModel.OV3660,
            supported_resolutions=[
                FrameSize.QVGA, FrameSize.VGA, FrameSize.SVGA, FrameSize.XGA,
                FrameSize.SXGA, FrameSize.UXGA, FrameSize.QXGA
            ],
            supported_formats=[PixelFormat.JPEG, PixelFormat.RGB565, PixelFormat.YUV422],
            max_fps=60,
            min_fps=1,
            has_autofocus=False,
            sensor_id=0x3660
        )
    }
    
    def __init__(self):
        self.current_config: Optional[CameraConfig] = None
        self.is_initialized: bool = False
        self.capabilities: Optional[CameraCapabilities] = None
        
    def get_supported_models(self) -> List[CameraModel]:
        """获取支持的摄像头型号"""
        return list(self.CAMERA_CAPABILITIES.keys())
    
    def get_capabilities(self, model: CameraModel) -> Optional[CameraCapabilities]:
        """获取指定型号的摄像头能力"""
        return self.CAMERA_CAPABILITIES.get(model)
    
    def validate_config(self, config: CameraConfig) -> Tuple[bool, List[str]]:
        """验证摄像头配置"""
        errors = []
        
        # 检查摄像头型号支持
        if config.model not in self.CAMERA_CAPABILITIES:
            errors.append(f"不支持的摄像头型号: {config.model.value}")
            return False, errors
        
        capabilities = self.CAMERA_CAPABILITIES[config.model]
        
        # 检查分辨率支持
        if config.frame_size not in capabilities.supported_resolutions:
            errors.append(f"摄像头 {config.model.value} 不支持分辨率 {config.frame_size.name}")
        
        # 检查像素格式支持
        if config.pixel_format not in capabilities.supported_formats:
            errors.append(f"摄像头 {config.model.value} 不支持像素格式 {config.pixel_format.value}")
        
        # 检查帧率范围
        if not (capabilities.min_fps <= config.fps <= capabilities.max_fps):
            errors.append(f"帧率 {config.fps} 超出支持范围 [{capabilities.min_fps}, {capabilities.max_fps}]")
        
        # 检查JPEG质量范围
        if config.pixel_format == PixelFormat.JPEG and not (1 <= config.jpeg_quality <= 63):
            errors.append(f"JPEG质量 {config.jpeg_quality} 必须在1-63范围内")
        
        # 检查图像处理参数范围
        for param, value in [
            ('brightness', config.brightness),
            ('contrast', config.contrast),
            ('saturation', config.saturation),
            ('sharpness', config.sharpness)
        ]:
            if not (-2 <= value <= 2):
                errors.append(f"{param} {value} 必须在-2到2范围内")
        
        # 检查降噪参数
        if not (0 <= config.denoise <= 8):
            errors.append(f"降噪参数 {config.denoise} 必须在0-8范围内")
        
        # 检查增益上限
        if not (0 <= config.gain_ceiling <= 6):
            errors.append(f"增益上限 {config.gain_ceiling} 必须在0-6范围内")
        
        return len(errors) == 0, errors
    
    def create_optimal_config(self, 
                            model: CameraModel,
                            target_resolution: Optional[FrameSize] = None,
                            target_fps: Optional[int] = None,
                            quality_priority: bool = True) -> CameraConfig:
        """创建优化的摄像头配置"""
        
        if model not in self.CAMERA_CAPABILITIES:
            raise ValueError(f"不支持的摄像头型号: {model.value}")
        
        capabilities = self.CAMERA_CAPABILITIES[model]
        config = CameraConfig(model=model)
        
        # 选择最佳分辨率
        if target_resolution and target_resolution in capabilities.supported_resolutions:
            config.frame_size = target_resolution
        else:
            # 默认选择VGA，如果不支持则选择最接近的
            if FrameSize.VGA in capabilities.supported_resolutions:
                config.frame_size = FrameSize.VGA
            else:
                config.frame_size = capabilities.supported_resolutions[len(capabilities.supported_resolutions)//2]
        
        # 选择最佳像素格式
        if PixelFormat.JPEG in capabilities.supported_formats:
            config.pixel_format = PixelFormat.JPEG
            config.jpeg_quality = 10 if quality_priority else 20
        else:
            config.pixel_format = capabilities.supported_formats[0]
        
        # 设置帧率
        if target_fps and capabilities.min_fps <= target_fps <= capabilities.max_fps:
            config.fps = target_fps
        else:
            config.fps = min(15, capabilities.max_fps)  # 默认15fps或最大支持帧率
        
        # 优化配置
        if quality_priority:
            config.frame_buffer_count = 2
            config.denoise = 2
            config.sharpness = 1
        else:
            config.frame_buffer_count = 1
            config.grab_mode = 1  # 获取最新帧
        
        return config
    
    def apply_dynamic_config(self, config: CameraConfig) -> bool:
        """动态应用配置更改"""
        try:
            # 验证配置
            is_valid, errors = self.validate_config(config)
            if not is_valid:
                logger.error(f"配置验证失败: {errors}")
                return False
            
            # 这里应该调用实际的ESP32摄像头API
            # 由于这是Python模拟实现，我们只记录配置更改
            logger.info(f"应用摄像头配置:")
            logger.info(f"  型号: {config.model.value}")
            logger.info(f"  分辨率: {config.frame_size.name} ({config.frame_size.value[0]}x{config.frame_size.value[1]})")
            logger.info(f"  像素格式: {config.pixel_format.value}")
            logger.info(f"  帧率: {config.fps} FPS")
            logger.info(f"  JPEG质量: {config.jpeg_quality}")
            
            self.current_config = config
            self.capabilities = self.CAMERA_CAPABILITIES[config.model]
            self.is_initialized = True
            
            return True
            
        except Exception as e:
            logger.error(f"应用配置时发生错误: {e}")
            return False
    
    def get_current_config(self) -> Optional[CameraConfig]:
        """获取当前配置"""
        return self.current_config
    
    def save_config(self, config: CameraConfig, filepath: str) -> bool:
        """保存配置到文件"""
        try:
            config_dict = config.to_dict()
            with open(filepath, 'w', encoding='utf-8') as f:
                json.dump(config_dict, f, indent=2, ensure_ascii=False)
            logger.info(f"配置已保存到: {filepath}")
            return True
        except Exception as e:
            logger.error(f"保存配置失败: {e}")
            return False
    
    def load_config(self, filepath: str) -> Optional[CameraConfig]:
        """从文件加载配置"""
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                config_dict = json.load(f)
            config = CameraConfig.from_dict(config_dict)
            logger.info(f"配置已从文件加载: {filepath}")
            return config
        except Exception as e:
            logger.error(f"加载配置失败: {e}")
            return None
    
    def auto_detect_camera(self) -> Optional[CameraModel]:
        """自动检测摄像头型号"""
        # 在实际实现中，这里会通过I2C读取传感器ID
        # 这里返回默认的OV2640作为示例
        logger.info("自动检测摄像头型号...")
        
        # 模拟检测过程
        detected_models = [CameraModel.OV2640, CameraModel.OV5640]
        for model in detected_models:
            logger.info(f"尝试检测 {model.value}...")
            # 在实际实现中会尝试初始化摄像头
            # 这里直接返回第一个支持的型号
            return model
        
        logger.warning("未检测到支持的摄像头")
        return None
    
    def get_status(self) -> Dict[str, Any]:
        """获取摄像头状态"""
        return {
            'initialized': self.is_initialized,
            'current_model': self.current_config.model.value if self.current_config else None,
            'current_resolution': f"{self.current_config.frame_size.value[0]}x{self.current_config.frame_size.value[1]}" if self.current_config else None,
            'current_fps': self.current_config.fps if self.current_config else None,
            'pixel_format': self.current_config.pixel_format.value if self.current_config else None,
            'capabilities': {
                'supported_resolutions': [res.name for res in self.capabilities.supported_resolutions] if self.capabilities else [],
                'supported_formats': [fmt.value for fmt in self.capabilities.supported_formats] if self.capabilities else [],
                'max_fps': self.capabilities.max_fps if self.capabilities else None,
                'has_autofocus': self.capabilities.has_autofocus if self.capabilities else False
            }
        }


# 预定义配置模板
class ConfigTemplates:
    """预定义的配置模板"""
    
    @staticmethod
    def high_quality_config(model: CameraModel = CameraModel.OV2640) -> CameraConfig:
        """高质量配置模板"""
        config = CameraConfig(
            model=model,
            frame_size=FrameSize.SXGA,
            pixel_format=PixelFormat.JPEG,
            jpeg_quality=8,
            fps=10,
            frame_buffer_count=2,
            denoise=3,
            sharpness=2,
            contrast=1
        )
        return config
    
    @staticmethod
    def high_speed_config(model: CameraModel = CameraModel.OV2640) -> CameraConfig:
        """高速配置模板"""
        config = CameraConfig(
            model=model,
            frame_size=FrameSize.VGA,
            pixel_format=PixelFormat.JPEG,
            jpeg_quality=25,
            fps=30,
            frame_buffer_count=1,
            grab_mode=1,
            denoise=0
        )
        return config
    
    @staticmethod
    def balanced_config(model: CameraModel = CameraModel.OV2640) -> CameraConfig:
        """平衡配置模板"""
        config = CameraConfig(
            model=model,
            frame_size=FrameSize.VGA,
            pixel_format=PixelFormat.JPEG,
            jpeg_quality=12,
            fps=15,
            frame_buffer_count=2,
            denoise=1,
            sharpness=1
        )
        return config
    
    @staticmethod
    def low_power_config(model: CameraModel = CameraModel.OV2640) -> CameraConfig:
        """低功耗配置模板"""
        config = CameraConfig(
            model=model,
            frame_size=FrameSize.QVGA,
            pixel_format=PixelFormat.JPEG,
            jpeg_quality=30,
            fps=5,
            frame_buffer_count=1,
            xclk_freq_hz=10000000  # 降低时钟频率
        )
        return config


def main():
    """测试函数"""
    # 创建摄像头管理器
    camera_manager = ESP32CameraManager()
    
    # 显示支持的摄像头型号
    print("支持的摄像头型号:")
    for model in camera_manager.get_supported_models():
        capabilities = camera_manager.get_capabilities(model)
        print(f"  {model.value}: 最大{capabilities.max_fps}FPS, "
              f"{len(capabilities.supported_resolutions)}种分辨率, "
              f"自动对焦: {'是' if capabilities.has_autofocus else '否'}")
    
    # 创建优化配置
    config = camera_manager.create_optimal_config(
        CameraModel.OV2640,
        target_resolution=FrameSize.VGA,
        target_fps=15,
        quality_priority=True
    )
    
    # 验证配置
    is_valid, errors = camera_manager.validate_config(config)
    print(f"\n配置验证: {'通过' if is_valid else '失败'}")
    if errors:
        for error in errors:
            print(f"  错误: {error}")
    
    # 应用配置
    if camera_manager.apply_dynamic_config(config):
        print("\n配置应用成功")
        status = camera_manager.get_status()
        print(f"当前状态: {json.dumps(status, indent=2, ensure_ascii=False)}")
    
    # 测试配置模板
    print("\n测试配置模板:")
    templates = [
        ("高质量", ConfigTemplates.high_quality_config()),
        ("高速度", ConfigTemplates.high_speed_config()),
        ("平衡", ConfigTemplates.balanced_config()),
        ("低功耗", ConfigTemplates.low_power_config())
    ]
    
    for name, template_config in templates:
        is_valid, _ = camera_manager.validate_config(template_config)
        print(f"  {name}配置: {'有效' if is_valid else '无效'} "
              f"({template_config.frame_size.name}, {template_config.fps}FPS)")


if __name__ == "__main__":
    main()